﻿using SkiaSharp;

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Xml.Linq;

using static System.Net.Mime.MediaTypeNames;

namespace Utils
{
    public static class DrawHelper
    {

        public static byte[] ToBytes(this SKSurface surface)
        {
            using var image = surface.Snapshot();
            using var data = image.Encode(SKEncodedImageFormat.Jpeg, 60);
            return data.ToArray();
        }

        public static SKImage CanvasByImage(Stream stream, Action<SKCanvas> action)
        {
            return CanvasByImage(SKImage.FromEncodedData(stream), action);
        }

        public static SKImage CanvasByImage(string path, Action<SKCanvas> action)
        {
            return CanvasByImage(SKImage.FromEncodedData(path), action);
        }


        public static SKBitmap ToBitmap(this SKImage image)
        {
            using (image)
            {
                return SKBitmap.FromImage(image);
            }
        }
        public static SKBitmap ResizeAuto(this SKBitmap skbBitmap, int width, int height, SKFilterQuality quality = SKFilterQuality.Medium)
        {
            if (height <= 0) return ResizeWithWidth(skbBitmap, width, quality);
            return ResizeWithHeight(skbBitmap, width, quality);
        }
        public static SKBitmap ResizeWithHeight(this SKBitmap skbBitmap, int height, SKFilterQuality quality = SKFilterQuality.High)
        {
            if (height <= 0 || height >= skbBitmap.Height) return skbBitmap;
            int width = (int)(1d * height / skbBitmap.Height * skbBitmap.Width);
            var resized = skbBitmap.Resize(new SKImageInfo(width, height), quality);
            if (resized == null)
            {
                return skbBitmap;
            }
            skbBitmap.Dispose();
            return resized;
        }

        /// <summary>
        /// 根据宽度调大小
        /// </summary>
        /// <param name="skbBitmap"></param>
        /// <param name="width"></param>
        /// <param name="quality"></param>
        /// <returns></returns>
        public static SKBitmap ResizeWithWidth(this SKBitmap skbBitmap, int width, SKFilterQuality quality = SKFilterQuality.High)
        {
            if (width <= 0 || width >= skbBitmap.Width) return skbBitmap;
            int height = (int)(1d * width / skbBitmap.Width * skbBitmap.Height);
            var resized = skbBitmap.Resize(new SKImageInfo(width, height), quality);
            if (resized == null)
            {
                return skbBitmap;
            }
            skbBitmap.Dispose();
            return resized;
        }

        public static SKImage ImageFromPath(string path)
        {
            return SKImage.FromEncodedData(path);
        }
        private static SKImage CanvasByImage(SKImage image, Action<SKCanvas> action)
        {
            using SKSurface surface = SKSurface.Create(new SKImageInfo(image.Width, image.Height));
            surface.Canvas.DrawImage(image, 0, 0);
            image.Dispose();
            action(surface.Canvas);
            return surface.Snapshot();
        }

        public static SKData ToData(this SKImage image, SKEncodedImageFormat format = SKEncodedImageFormat.Jpeg, int quality = -1)
        {
            using (image)
            {
                return image.Encode(format, quality);
            }
        }

        public static byte[] ToBytes(this SKBitmap image, SKEncodedImageFormat format = SKEncodedImageFormat.Jpeg, int quality = -1)
        {
            if (quality <= 0)
            {
                var s = 500;
                var x = Math.Min(image.Width, image.Height);
                quality = 100 - 100 * x / (2 * s + 100 / 50 * x);
            }
            using (image)
            {
                using SKData p = image.Encode(format, quality);
                return p.ToArray();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="image"></param>
        /// <param name="format"></param>
        /// <param name="quality"></param>
        /// <returns></returns>
        public static byte[] ToBytes(this SKImage image, SKEncodedImageFormat format = SKEncodedImageFormat.Jpeg, int quality = -1)
        {
            if (quality <= 0)
            {
                var s = 500;
                var x = Math.Min(image.Width, image.Height);
                quality = 100 - 100 * x / (2 * s + 100 / 50 * x);
            }
            using (image)
            {
                using SKData p = image.Encode(format, quality);
                return p.ToArray();
            }
        }


        /// <summary>
        /// 相对矩形
        /// </summary>
        /// <param name="canvas"></param>
        /// <param name="startX"></param>
        /// <param name="startY"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="w"></param>
        /// <param name="h"></param>
        /// <param name="sKPaint"></param>
        private static void RelativeDrawRect(this SKCanvas canvas, float startX, float startY, float x, float y, float w, float h, SKPaint paint)
        {
            canvas.DrawRect(SKRect.Create(startX + x, startY + y, w, h), paint);
        }

        /// <summary>
        /// 圆角矩形
        /// </summary>
        /// <param name="canvas"></param>
        /// <param name="filename"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="radius"></param>
        public static void DrawImageClipRoundRect(this SKCanvas canvas, string filename, float x, float y, float radius)
        {
            canvas.Save();
            var path = new SKPath();
            path.AddCircle(x, y, radius);
            canvas.ClipPath(path);
            using (var avatarImage = SKImage.FromEncodedData(SKData.Create(filename)))
            {
                //定义绘制头像的位置和尺寸
                var rect = SKRect.Create(x - radius, y - radius, radius * 2, radius * 2);
                //绘制头像
                canvas.DrawImage(avatarImage, rect);
            }

            //恢复画布状态为全图绘制状态
            canvas.Restore();
        }
        public static void DrawImageClipRoundRect(this SKCanvas canvas, string filename, float x, float y, float width, float height, int radius)
        {
            canvas.Save();
            canvas.ClipRoundRect(new SKRoundRect(SKRect.Create(x, y, width, height), radius, radius));
            using (var avatarImage = SKImage.FromEncodedData(filename))
            {
                //定义绘制头像的位置和尺寸
                var rect = SKRect.Create(x, y, width, height);
                //绘制头像
                canvas.DrawImage(avatarImage, rect);
            }

            //恢复画布状态为全图绘制状态
            canvas.Restore();
        }

        /// <summary>
        /// 贴图
        /// </summary>
        /// <param name="canvas"></param>
        /// <param name="filename"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public static void DrawImage(this SKCanvas canvas, string filename, float x, float y, float width, float height)
        {
            //保存当前画布状态，即正常全图绘制状态
            canvas.Save();
            using (var avatarImage = SKImage.FromEncodedData(filename))
            {
                //定义绘制头像的位置和尺寸
                var rect = SKRect.Create(x, y, width, height);
                //绘制头像
                canvas.DrawImage(avatarImage, rect);
            }
            //恢复画布状态为全图绘制状态
            canvas.Restore();
        }

        //画单行文字扩展方法
        public static void DrawSingleLineText(this SKCanvas canvas, string text, float x, float y, SKPaint paint)
        {
            //定义一个矩形，此矩形为计算文字区域的结果
            var tRect = new SKRect();
            //计算文字占用区域
            paint.MeasureText(text, ref tRect);
            //调用画布的画字方法
            canvas.DrawText(text, x - tRect.Left, y - tRect.Top, paint);
        }
        public static void DrawSingleLineTextCenter(this SKCanvas canvas, string text, float x, float y, SKPaint paint)
        {
            //定义一个矩形，此矩形为计算文字区域的结果
            var tRect = new SKRect();
            //计算文字占用区域
            paint.MeasureText(text, ref tRect);
            //调用画布的画字方法
            canvas.DrawText(text, x - tRect.Left - tRect.Width / 2, y - tRect.Top, paint);
        }
        public static void DrawMuiltLineText(this SKCanvas canvas, string text, float x, float y, SKPaint paint, float maxWidth, int maxLines)
        {
            //已写出行数
            int lines = 0;
            //省略号宽度
            var ellipseWidth = paint.MeasureText("...");
            //如果文字没写完且已写行数小于最大行数，则继续写出
            while (!string.IsNullOrEmpty(text) && lines < maxLines)
            {
                //单行文字
                string lineStr;
                //单行文字长度
                long strLength;
                //非最后一行
                if (lines != maxLines - 1)
                {
                    //调用BreakText方法，可计算指定宽度能写出多少文字
                    strLength = paint.BreakText(text, maxWidth, out float ww, out lineStr);
                }
                //最后一行
                else
                {
                    //调用BreakText方法计算单行文字长度，这里需减去省略号宽度
                    strLength = paint.BreakText(text, maxWidth - ellipseWidth, out float ww, out lineStr);
                    //假如字还没写完，需加省略号
                    if (strLength < text.Length)
                    {
                        lineStr += "...";
                    }
                }
                //文字矩形
                var tRect = new SKRect();
                //计算文字矩形
                paint.MeasureText(lineStr, ref tRect);
                //计算坐标
                var tPoint = new SKPoint
                {
                    X = x - tRect.Left,
                    //这里注意Y坐标需要加上行高
                    Y = y + lines * paint.FontSpacing - tRect.Top
                };
                //写出一行文字
                canvas.DrawText(lineStr, tPoint, paint);
                //已写出行数加1
                lines++;
                //取剩余文字
                text = text[(int)strLength..];
            }
        }
    }
}
